
## Snakes on a Payload
## Copyright (C) 2011 CORE Security Technologies
##
## This program is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License
## as published by the Free Software Foundation; either version 2
## of the License, or (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
##
## Authors:
## 2011/09/11 - Pedro Varangot (pvarangot@)
## 2011/09/11 - Fernando Russ (fruss@)



import struct
class Relocation(object):
    
    RELS = {}
    
    class RelocType:
        END = 0
        REBASE = 1
        JMPSLOT = 2
        LOADLIB = 3
        
        
    def __init__(self, elf, arch, name, offset, info, symvalue):
        self.elf = elf
        self.arch = arch
        self.name = name
        self.offset = offset
        self.info = info        
        self.value, self.addend, self.symbol = self.parseSymbol( symvalue )

    @staticmethod
    def byType( name ):
        rel_type_impl = Relocation.RELS.get(name, None)
        if rel_type_impl == None:
            return UnsupportedRelocationType
        return rel_type_impl

    @staticmethod
    def register( klass ):
        Relocation.RELS[klass.NAME] = klass
        return klass
        
    @staticmethod
    def emitEntry(writer, arch, **args):
        writer.write( struct.pack( arch.endianess + "I", args.get("type") ) )
        writer.write( struct.pack( arch.address, args.get("offset", 0) ) )
                        
        _rtl_rel_name = args.get("name", "\x00" * 128)
        if len(_rtl_rel_name) > 128:
            raise Exception("symbol name:'%s' too long (> 127)" % _rtl_rel_name)
        # pad the name
        _rtl_rel_name = _rtl_rel_name + ("\x00" * (128-len(_rtl_rel_name)))
        writer.write( _rtl_rel_name )
    
    def parseSymbol(self, values):
        # generic parsing of a relocation symbol        
        if values[-2] in ("-","+"):
            addend = int( "".join(values[-2:]),16)
        else:
            addend = 0        
        name   = values[1]
        value  = int(values[0],16)
        
        return value, addend, name
        
    def apply(self, current_section, context): pass

    
class UnsupportedRelocationType(Relocation): 
    NAME = "UnsupportedRelocationType"
    
    def apply(self, current_section, context):
        raise Exception("I'dont know who to apply relocations of type '%s'" % self.name)
        
    def parseSymbol(self, values): return "",0,"" # we don't know how to parse this


